`include  "defines.v"
module wrAXI(
  input clk,
  input rst_n,
  
  input  wr_addr_valid_i,
  input  [`ADDR_W-1:0]wr_addr_i,
  input [7:0] wr_strb_i,
  input [127:0]wr_data_i,
  output wr_data_valid_o,

  input                               axi_aw_ready     ,       
  output                              axi_aw_valid     ,   
  output [`AXI_ADDR_WIDTH-1:0]        axi_aw_bits_addr ,   
  output [2:0]                        axi_aw_bits_prot ,   
  output [`AXI_ID_WIDTH-1:0]          axi_aw_bits_id   ,
  output [`AXI_USER_WIDTH-1:0]        axi_aw_bits_user ,     
  output [7:0]                        axi_aw_bits_len  ,      
  output [2:0]                        axi_aw_bits_size ,
  output [1:0]                        axi_aw_bits_burst,
  output                              axi_aw_bits_lock ,   
  output [3:0]                        axi_aw_bits_cache,   
  output [3:0]                        axi_aw_bits_qos  ,   
  
  input                               axi_w_ready      ,  
  output                              axi_w_valid      ,
  output [`AXI_DATA_WIDTH-1:0]        axi_w_bits_data  ,   
  output [`AXI_DATA_WIDTH/8-1:0]      axi_w_bits_strb  ,   
  output                              axi_w_bits_last  ,   
  
  output                              axi_b_ready       ,
  input                               axi_b_valid       ,
  input  [1:0]                        axi_b_bits_resp   ,  
  input  [`AXI_ID_WIDTH-1:0]          axi_b_bits_id     ,
  input  [`AXI_USER_WIDTH-1:0]        axi_b_bits_user    
);
wire isMMIO = wr_addr_valid_i && ~wr_addr_i[`ADDR_W-1];

parameter IDLE = 4'b0001,
          AW   = 4'b0010,
          W    = 4'b0100,
          B    = 4'b1000;

reg [3:0] cur_state;
reg [3:0] nxt_state;
always@(posedge clk or negedge rst_n)
  if(~rst_n)
    cur_state <= IDLE;
  else 
    cur_state <= nxt_state;

always@(*)begin
  case(cur_state)
    IDLE:if(wr_addr_valid_i) nxt_state = AW; else nxt_state = IDLE;
    AW  :if(axi_aw_ready && axi_aw_valid) nxt_state = W; else nxt_state=AW;
    W   :if(axi_w_ready  && axi_w_valid && axi_w_bits_last)nxt_state=B;else nxt_state=W;
    B   :if(axi_b_ready  && axi_b_valid) nxt_state = IDLE;else nxt_state=B;
    default:nxt_state=IDLE;
  endcase
end

always@(*)begin
  if(axi_b_ready  && axi_b_valid && (axi_b_bits_resp != 2'b00))begin
    $display("wr recv error resp");
    $finish;
  end
end


reg [1:0]wr_cnt;
always@(posedge clk or negedge rst_n)
  if(~rst_n)
    wr_cnt <= 'd0;
  else if((cur_state == W) && ~isMMIO)begin
    if(axi_w_ready && axi_w_valid)
      wr_cnt <= wr_cnt + 1'b1;
    else 
      wr_cnt <= wr_cnt;
  end else
    wr_cnt <= 'd0;

assign axi_aw_valid      = (cur_state == AW);
assign axi_aw_bits_addr  = isMMIO ? wr_addr_i : {wr_addr_i[31:4] , 4'd0};
assign axi_aw_bits_prot  = 'd0;
assign axi_aw_bits_id    = 'd1;
assign axi_aw_bits_user  = 'd0;
assign axi_aw_bits_len   = isMMIO ? 'd0    : 'd1   ;
assign axi_aw_bits_size  = isMMIO ? 3'b010 : 3'b011;
assign axi_aw_bits_burst = 2'b01  ;
assign axi_aw_bits_lock  =  'd0   ;
assign axi_aw_bits_cache =  'b0010;
assign axi_aw_bits_qos   =  'd0   ;

assign axi_w_valid       = (cur_state == W);
assign axi_w_bits_data   = (wr_cnt == 'd0) ? wr_data_i[63:0] : wr_data_i[127:64];
assign axi_w_bits_strb   = isMMIO ? (wr_addr_i[2] ? wr_strb_i[7:4] : wr_strb_i[3:0])  : 8'hFF;
assign axi_w_bits_last   = (wr_cnt == 2'd1) || isMMIO;

assign axi_b_ready       = (cur_state == B);
assign wr_data_valid_o   = axi_b_valid && axi_b_ready && (axi_b_bits_resp == 'd0);

endmodule